﻿using System.Net;
using System.IO;
using System.Web.Caching;
using System.Collections;
using System.Collections.Specialized;
using System.Text;
using System.Threading.Tasks;
using System.Web.Hosting;
namespace System.Web
{
    public class NetHttpResponse : HttpResponseBase
    {
        private HttpListenerContext _netContext;
        private HttpListenerResponse _netResponse;
        private HttpCachePolicyBase _cache;
        //
        private bool _headersWritten;
        private bool _completed;
        private bool _flushing;
        private bool _ended;

        public NetHttpResponse(WebHostWorkerRequest wr, NetHttpContext context)
        {
            Context = context;
            _netContext = wr.NetContext;
            _netResponse = _netContext.Response;
        }
        internal void Dispose()
        {
            //if (_httpWriter != null)
            //    _httpWriter.RecycleBuffers();
        }


        #region HttpResponseBase

        public override void AddCacheDependency(params CacheDependency[] dependencies) { }
        public override void AddCacheItemDependencies(ArrayList cacheKeys) { }
        public override void AddCacheItemDependencies(string[] cacheKeys) { }
        public override void AddCacheItemDependency(string cacheKey) { }
        public override void AddFileDependencies(string[] filenames) { }
        public override void AddFileDependencies(ArrayList filenames) { }
        public override void AddFileDependency(string filename) { }

        public override void AddHeader(string name, string value)
        {
            _netResponse.AddHeader(name, value);
        }

        public override void AppendCookie(HttpCookie cookie)
        {
            _netResponse.AppendCookie(new Cookie
            {
                Name = cookie.Name,
                Value = cookie.Value,
                Path = cookie.Path,
            });
        }

        public override void AppendHeader(string name, string value)
        {
            _netResponse.AppendHeader(name, value);
        }

        public override void AppendToLog(string param) { }
        public override string ApplyAppPathModifier(string virtualPath) { return null; }

        public override void BinaryWrite(byte[] buffer)
        {
            _netResponse.OutputStream.Write(buffer, 0, buffer.Length);
        }

        public override void Clear() { }
        public override void ClearContent() { }
        public override void ClearHeaders() { }

        public override void Close()
        {
            _netResponse.Close();
        }

        public override void DisableKernelCache() { }

        public override void End()
        {
            //if (Context.IsInCancellablePeriod)
            //    Thread.CurrentThread.Abort(new NetHttpApplication.CancelModuleException(false));
            //else 
            if (!_flushing)
            {
                Flush();
                _ended = true;
                if (Context.NetApplicationInstance != null)
                    Context.NetApplicationInstance.CompleteRequest();
            }
        }

        public void Flush()
        {
            if (_completed)
                throw new HttpException("Cannot_flush_completed_response");
            Flush(false);
        }
        private void Flush(bool finalFlush)
        {
            if (!_completed && !_flushing)
            {
                _flushing = true;
                try { _netResponse.OutputStream.Flush(); }
                finally
                {
                    _flushing = false;
                    if (finalFlush && _headersWritten)
                        _completed = true;
                }
            }
        }

        public override void Pics(string value) { }

        public override void Redirect(string url)
        {
            _netResponse.Redirect(url);
        }

        public override void Redirect(string url, bool endResponse)
        {
            _netResponse.Redirect(url);
            if (endResponse)
                End();
        }

        public override void RedirectPermanent(string url) { }
        public override void RedirectPermanent(string url, bool endResponse)
        {
            if (endResponse)
                End();
        }

        public override void RemoveOutputCacheItem(string path) { }
        public override void RemoveOutputCacheItem(string path, string providerName) { }

        public override void SetCookie(HttpCookie cookie)
        {
            _netResponse.SetCookie(new Cookie
            {
                Name = cookie.Name,
                Value = cookie.Value,
                Expires = cookie.Expires,
            });
        }

        public override void TransmitFile(string filename) { }
        public override void TransmitFile(string filename, long offset, long length) { }

        public override void Write(char ch)
        {
            var bytes = Encoding.UTF8.GetBytes(new[] { ch });
            _netResponse.OutputStream.Write(bytes, 0, bytes.Length);
            _netResponse.OutputStream.Flush();
        }

        public override void Write(object obj)
        {
            throw new IndexOutOfRangeException("WHAT");
        }

        public override void Write(string s)
        {
            var bytes = Encoding.UTF8.GetBytes(s);
            _netResponse.OutputStream.Write(bytes, 0, bytes.Length);
            _netResponse.OutputStream.Flush();
        }

        public override void Write(char[] buffer, int index, int count)
        {
            var bytes = Encoding.UTF8.GetBytes(buffer);
            _netResponse.OutputStream.Write(bytes, 0, bytes.Length);
            _netResponse.OutputStream.Flush();
        }

        public override void WriteFile(string filename)
        {
        }

        public override void WriteFile(string filename, bool readIntoMemory)
        {
        }

        public override void WriteFile(IntPtr fileHandle, long offset, long size)
        {
        }

        public override void WriteFile(string filename, long offset, long size)
        {
        }

        public override void WriteSubstitution(HttpResponseSubstitutionCallback callback)
        {
        }

        public override bool Buffer
        {
            get { return false; }
            set { }
        }

        public override bool BufferOutput
        {
            get { return false; }
            set { }
        }

        public override HttpCachePolicyBase Cache
        {
            get { return _cache; }
        }

        public override string CacheControl
        {
            get { return null; }
            set { }
        }

        public override string Charset
        {
            get { return null; }
            set { }
        }

        public override Encoding ContentEncoding
        {
            get { return _netResponse.ContentEncoding; }
            set { _netResponse.ContentEncoding = value; }
        }

        public override string ContentType
        {
            get { return _netResponse.ContentType; }
            set { _netResponse.ContentType = value; }
        }

        public override HttpCookieCollection Cookies
        {
            get
            {
                var cookies = new HttpCookieCollection();
                foreach (Cookie cookie in _netResponse.Cookies)
                    cookies.Add(new HttpCookie(cookie.Name, cookie.Value)
                    {
                        Expires = cookie.Expires,
                    });
                return cookies;
            }
        }

        public override int Expires
        {
            get { return 0; }
            set { }
        }

        public override DateTime ExpiresAbsolute
        {
            get { return DateTime.Now; }
            set { }
        }

        public override Stream Filter
        {
            get { return null; }
            set { }
        }

        public override Encoding HeaderEncoding
        {
            get { return null; }
            set { }
        }

        public override NameValueCollection Headers
        {
            get { return _netResponse.Headers; }
        }

        public override bool IsClientConnected
        {
            get { return true; }
        }

        public override bool IsRequestBeingRedirected
        {
            get { return false; }
        }

        public override TextWriter Output
        {
            get { return null; }
            set { }
        }

        public override Stream OutputStream
        {
            get { return _netResponse.OutputStream; }
        }

        public override string RedirectLocation
        {
            get { return _netResponse.RedirectLocation; }
            set { _netResponse.RedirectLocation = value; }
        }

        public override string Status
        {
            get { return "Status"; }
            set { }
        }

        public override int StatusCode
        {
            get { return _netResponse.StatusCode; }
            set { _netResponse.StatusCode = value; }
        }

        public override string StatusDescription
        {
            get { return _netResponse.StatusDescription; }
            set { _netResponse.StatusDescription = value; }
        }

        public override int SubStatusCode
        {
            get { return 0; }
            set { }
        }

        public override bool SuppressContent
        {
            get { return false; }
            set { }
        }

        public override bool TrySkipIisCustomErrors
        {
            get { return false; }
            set { }
        }

        #endregion

        internal NetHttpContext Context { get; set; }

        internal void FinalFlushAtTheEndOfRequestProcessing()
        {
            Flush(true);
        }

        internal void ReportRuntimeError(Exception ex, bool canThrow, bool localExecute) { Write(FormatExceptionMessage(ex, null).ToString()); }
        private StringBuilder FormatExceptionMessage(Exception ex, string[] strings)
        {
            var b = new StringBuilder(0x1000);
            if (strings != null)
                for (int i = 0; i < strings.Length; i++)
                    b.Append(strings[i]);
            for (Exception ex2 = ex; ex2 != null; ex2 = ex2.InnerException)
            {
                if (ex2 == ex)
                    b.Append("\r\n\r\nException: ");
                else
                    b.Append("\r\n\r\nInnerException: ");
                b.Append(ex2.GetType().FullName);
                b.Append("\r\nMessage: ");
                b.Append(ex2.Message);
                b.Append("\r\nStackTrace: ");
                b.Append(ex2.StackTrace);
            }
            return b;
        }

        internal void InitResponseWriter() { }

        internal void GenerateResponseHeadersForHandler()
        {
        }
    }
}
